﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MonPocGarage.ArmyContracts;
using MonPocGarage.ArmyContracts.Common.Enums;
using MonPocGarage.ArmyData;
using MonPocGarage.Common.Logging;
using MonPocGarage.GUI.Helpers;

namespace MonPocGarage.GUI
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public Army m_Army = new Army();
        private string m_CurrentFileName;

        public MainWindow()
        {
            m_CurrentFileName = string.Empty;
            m_Army = ArmyInstance.GetArmy(m_CurrentFileName);            
            InitializeComponent();
            LogHandler.LogMessage("MonPoc Garage Successfully Started.", MessageLevel.DEBUG);
        }

        #region *** PROPERTIES FOR BINDING ***

        public string ArmyName
        {
            get
            {
                return m_Army.ArmyName;
            }
        }

        public string ArmyFaction
        {
            get
            {
                return m_Army.ArmyFaction.ToString();
            }
        }

        public ObservableCollection<Unit> ArmyUnits
        {
            get
            {
                return m_Army.ArmyUnits;
            }
        }

        public bool HasUnits
        {
            get { return m_Army.ArmyUnits.Count > 0; }
        }

        public ObservableCollection<Building> ArmyBuildings
        {
            get { return m_Army.ArmyBuildings; }
        }

        public ObservableCollection<Monster> ArmyMonsters
        {
            get { return m_Army.ArmyMonsters; }
        }

        #endregion

        #region *** ARMY LOAD AND SAVE CLICK METHODS ***

        protected void btnLoadArmy_Click(object sender, RoutedEventArgs e)
        {
            Microsoft.Win32.OpenFileDialog dlg = new Microsoft.Win32.OpenFileDialog();
            dlg.FileName = string.Empty; // Default file name
            dlg.DefaultExt = ".xml"; // Default file extension
            //Put this back in later
            //dlg.Filter = "MonPoc Garage Armies (*.xml) |*.xml|All Files (*.*)|*.*"; // Filter files by extension
            //We should set this to something better, maybe store a last-used or user-configurable directory?
            dlg.InitialDirectory = Environment.CurrentDirectory;
            dlg.Title = "Load Army";

            // Show open file dialog box
            bool? result = dlg.ShowDialog();
            // Process open file dialog box results
            if (result == true)
            {
                // Open army file
                m_CurrentFileName = dlg.FileName;
                m_Army = ArmyInstance.GetArmy(m_CurrentFileName);
                InitializeComponent();
            }
        }

        protected void btnSaveArmy_Click(object sender, RoutedEventArgs e)
        {
            //lvDetailsView.ItemTemplate = (DataTemplate)Resources["unitAddTemplate"];
            //lvDetailsView.ItemsSource = new List<Unit> { BuildArmy.GetUnits().First() };
        }

        #endregion

        #region *** PICK LIST EVENTS ***

        private void pickListMonsterTemplate_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            string monsterName = (
                                     (Label)
                                     ((StackPanel)sender).FindName("lblMonsterID")
                                 ).Content.ToString();
            if (e.ClickCount == 1)
            {
                LoadDetailsView(GetMonsterByID(monsterName));
            }
            else //Double (or more) click
            {
                bool isAdded = AddMonsterToArmy(monsterName);
                if (!isAdded)
                {
                    lblResult.Content = "Unable to Add Monster " + monsterName + " to your Army.";
                }
            }
        }

        private void pickListUnitTemplate_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            string unitID = (
                                     (Label)
                                     ((StackPanel)sender).FindName("lblUnitID")
                                 ).Content.ToString();
            if (e.ClickCount == 1)
            {
                LoadDetailsView(GetUnitByID(unitID));
            }
            else //Double (or more) click
            {
                bool isAdded = AddUnitToArmy(unitID);
                if (!isAdded)
                {
                    lblResult.Content = "Unable to Add Unit " + unitID + " to your Army.";
                }
            }
        }

        private void pickListBuildingTemplate_OnMouseDown(object sender, MouseButtonEventArgs e)
        {
            string buildingName = (
                                     (Label)
                                     ((StackPanel)sender).FindName("lblBuildingID")
                                 ).Content.ToString();
            if (e.ClickCount == 1)
            {
                LoadDetailsView(GetBuildingByID(buildingName));
            }
            else //Double (or more) click
            {
                bool isAdded = AddBuildingToArmy(buildingName);
                if (!isAdded)
                {
                    lblResult.Content = "Unable to Add Building " + buildingName + " to your Army.";
                }
            }
        }

        #endregion

        #region *** CURRENT ARMY EVENTS ***

        private void spMonsterForm1_LostFocus(object sender, RoutedEventArgs e)
        {
            spMonsterForm1.Background = Brushes.Transparent;
        }

        private void spMonsterForm1_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            spMonsterForm1.Focusable = true;
            spMonsterForm1.Focus();
            spMonsterForm1.Background = Brushes.DodgerBlue;
            //Get Monster Name from Display
            //LoadDetailsView();
        }

        private void spMonsterForm2_LostFocus(object sender, RoutedEventArgs e)
        {
            spMonsterForm2.Background = Brushes.Transparent;
        }

        private void spMonsterForm2_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            spMonsterForm2.Focusable = true;
            spMonsterForm2.Focus();
            spMonsterForm2.Background = Brushes.DodgerBlue;
            //Get Monster Name from Display
            //LoadDetailsView();
        }

        private void unitListTemplate_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            string unitName = (((Grid)sender).FindName("lblUnitID") as Label).Content.ToString();
            LoadDetailsView(GetUnitByID(unitName));
        }

        private void buildingListTemplate_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            string buildingName = (((Grid)sender).FindName("lblBuildingID") as Label).Content.ToString();
            LoadDetailsView(GetBuildingByID(buildingName));
        }

        private void DeleteUnit_Click(object sender, RoutedEventArgs e)
        {
            string unitName = ((Label)((Grid)((Popup)((ContextMenu)((MenuItem)sender).Parent).Parent).PlacementTarget).FindName("lblUnitID")).Content.ToString();
            RemoveUnitFromArmy(unitName);
        }

        private void DeleteBuilding_Click(object sender, RoutedEventArgs e)
        {
            string buildingName = ((Label)((Grid)((Popup)((ContextMenu)((MenuItem)sender).Parent).Parent).PlacementTarget).FindName("lblBuildingID")).Content.ToString();
            RemoveBuildingFromArmy(buildingName);
        }

        private void DeleteMonsterForm1_Click(object sender, RoutedEventArgs e)
        {
            RemoveMonsterFromArmy(lblMonsterForm1ID.Content.ToString());
            //spMonsterForm1.DataContext = m_Army.ArmyMonsters.FirstOrDefault();
        }

        private void DeleteMonsterForm2_Click(object sender, RoutedEventArgs e)
        {
            RemoveMonsterFromArmy(lblMonsterForm2ID.Content.ToString());
            //spMonsterForm2.DataContext = m_Army.ArmyMonsters.Skip(1).FirstOrDefault();
        }
        
        #endregion

        #region *** ARMY MANAGEMENT METHODS ***

        private bool AddMonsterToArmy(string monsterID)
        {
            bool success;
            try
            {
                Monster monster = GetMonsterByID(monsterID);
                if (monster == null)
                {
                    LogHandler.LogMessage(string.Format("AddMonsterToArmy: Unable to locate Monster {0} in Monster List", monsterID), MessageLevel.WARN);
                    success = false;
                }
                else
                {
                    LogHandler.LogMessage(string.Format("AddMonsterToArmy: Found Monster {0} in Monster List", monsterID), MessageLevel.DEBUG);
                    success = m_Army.AddMonster(monster);
                    LogHandler.LogMessage(string.Format("AddMonsterToArmy: Added Monster {0} to Army List", monsterID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("AddMonsterToArmy: Exception while locating Monster {0} in Monster List", monsterID), ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        private bool RemoveMonsterFromArmy(string monsterID)
        {
            bool success;
            try
            {
                Monster monster = m_Army.ArmyMonsters
                                                .Where(m => m.MonsterID == monsterID)
                                                .FirstOrDefault();
                if (monster == null)
                {
                    LogHandler.LogMessage(string.Format("RemoveMonsterFromArmy: Unable to locate Monster {0} in Army List", monsterID), MessageLevel.WARN);
                    success = false;
                }
                else
                {
                    LogHandler.LogMessage(string.Format("RemoveMonsterFromArmy: Found Monster {0} in Army List", monsterID), MessageLevel.DEBUG);
                    success = m_Army.RemoveMonster(monster);
                    LogHandler.LogMessage(string.Format("RemoveMonsterFromArmy: Removed Monster {0} from Army List", monsterID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("RemoveMonsterFromArmy: Exception while locating Monster {0} in Army List", monsterID), ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        private static Monster GetMonsterByID(string monsterID)
        {
            Monster monster;
            try
            {
                monster = BuildArmy.GetMonsters()
                                        .Where(m => m.MonsterID == monsterID)
                                        .FirstOrDefault();
                if (monster == null)
                {
                    LogHandler.LogMessage(string.Format("GetMonsterByName: Unable to locate Monster {0} in Monster List", monsterID), MessageLevel.WARN);
                }
                else
                {
                    LogHandler.LogMessage(string.Format("GetMonsterByName: Found Monster {0} in Monster List", monsterID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("GetMonsterByName: Exception while locating Monster {0} in Monster List", monsterID), ex, MessageLevel.ERROR);
                monster = null;
            }
            return monster;
        }

        private bool AddUnitToArmy(string unitID)
        {
            bool success;
            try
            {
                Unit unit = GetUnitByID(unitID);
                if (unit == null)
                {
                    LogHandler.LogMessage(string.Format("AddUnitToArmy: Unable to locate Unit {0} in Unit List", unitID), MessageLevel.WARN);
                    success = false;
                }
                else
                {
                    LogHandler.LogMessage(string.Format("AddUnitToArmy: Found Unit {0} in Unit List", unitID), MessageLevel.DEBUG);
                    success = m_Army.AddUnit(unit);
                    LogHandler.LogMessage(string.Format("AddUnitToArmy: Added Unit {0} to Army List", unitID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("AddUnitToArmy: Exception while locating Unit {0} in Unit List", unitID), ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        private bool RemoveUnitFromArmy(string unitID)
        {
            bool success;
            try
            {
                Unit unit = m_Army.ArmyUnits
                                    .Where(m => m.UnitID == unitID)
                                    .FirstOrDefault();
                if (unit == null)
                {
                    LogHandler.LogMessage(string.Format("RemoveUnitFromArmy: Unable to locate Unit {0} in Army List", unitID), MessageLevel.WARN);
                    success = false;
                }
                else
                {
                    LogHandler.LogMessage(string.Format("RemoveUnitFromArmy: Found Unit {0} in Army List", unitID), MessageLevel.DEBUG);
                    success = m_Army.RemoveUnit(unit);
                    LogHandler.LogMessage(string.Format("RemoveUnitFromArmy: Removed Unit {0} from Army List", unitID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("RemoveUnitFromArmy: Exception while locating Unit {0} in Unit List", unitID), ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        private static Unit GetUnitByID(string unitID)
        {
            Unit unit;
            try
            {
                unit = BuildArmy.GetUnits()
                                    .Where(m => m.UnitID == unitID)
                                    .FirstOrDefault();
                if (unit == null)
                {
                    LogHandler.LogMessage(string.Format("GetUnitByName: Unable to locate Unit {0} in Unit List", unitID), MessageLevel.WARN);
                }
                else
                {
                    LogHandler.LogMessage(string.Format("GetUnitByName: Found Unit {0} in Unit List", unitID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("GetUnitByName: Exception while locating Unit {0} in Unit List", unitID), ex, MessageLevel.ERROR);
                unit = null;
            }
            return unit;
        }

        private bool AddBuildingToArmy(string buildingID)
        {
            bool success;
            try
            {
                Building building = GetBuildingByID(buildingID);
                if (building == null)
                {
                    LogHandler.LogMessage(string.Format("AddBuildingToArmy: Unable to locate Building {0} in Building List", buildingID), MessageLevel.WARN);
                    success = false;
                }
                else
                {
                    LogHandler.LogMessage(string.Format("AddBuildingToArmy: Found Building {0} in Building List", buildingID), MessageLevel.DEBUG);
                    success = m_Army.AddBuilding(building);
                    LogHandler.LogMessage(string.Format("AddBuildingToArmy: Added Building {0} to Army List", buildingID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("AddBuildingToArmy: Exception while locating Building {0} in Building List", buildingID), ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        private bool RemoveBuildingFromArmy(string buildingID)
        {
            bool success;
            try
            {
                Building building = m_Army.ArmyBuildings
                                                .Where(m => m.BuildingID == buildingID)
                                                .FirstOrDefault();
                if (building == null)
                {
                    LogHandler.LogMessage(string.Format("RemoveBuildingFromArmy: Unable to locate Building {0} in Army List", buildingID), MessageLevel.WARN);
                    success = false;
                }
                else
                {
                    LogHandler.LogMessage(string.Format("RemoveBuildingFromArmy: Found Building {0} in Army List", buildingID), MessageLevel.DEBUG);
                    success = m_Army.RemoveBuilding(building);
                    LogHandler.LogMessage(string.Format("RemoveBuildingFromArmy: Removed Building {0} from Army List", buildingID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("RemoveBuildingFromArmy: Exception while locating Building {0} in Building List", buildingID), ex, MessageLevel.ERROR);
                success = false;
            }
            return success;
        }

        private static Building GetBuildingByID(string buildingID)
        {
            Building building;
            try
            {
                building = BuildArmy.GetBuildings()
                                        .Where(m => m.BuildingID == buildingID)
                                        .FirstOrDefault();
                if (building == null)
                {
                    LogHandler.LogMessage(string.Format("GetBuildingByName: Unable to locate Building {0} in Building List", buildingID), MessageLevel.WARN);
                }
                else
                {
                    LogHandler.LogMessage(string.Format("GetBuildingByName: Found Building {0} in Building List", buildingID), MessageLevel.DEBUG);
                }
            }
            catch (Exception ex)
            {
                LogHandler.LogException(string.Format("GetBuildingByName: Exception while locating Building {0} in Building List", buildingID), ex, MessageLevel.ERROR);
                building = null;
            }
            return building;
        }

        #endregion

        #region *** DETAILS VIEW LOAD METHODS ***

        private void LoadDetailsView(Monster monster)
        {
            if (spDetailsView.DataContext != monster)
            {
                spDetailsView.DataContext = monster;
            }
        }

        private void LoadDetailsView(Building building)
        {
            if (spDetailsView.DataContext != building)
            {
                spDetailsView.DataContext = building;
            }
        }

        private void LoadDetailsView(Unit unit)
        {
            if (spDetailsView.DataContext != unit)
            {
                spDetailsView.DataContext = unit;
            }
        }


        #endregion

        private void cmbFaction_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            ((ObjectDataProvider)Resources["odpUnitListProvider"]).MethodParameters[0] = cmbFaction.SelectedValue;
            ((ObjectDataProvider) Resources["odpMonsterListProvider"]).MethodParameters[0] = cmbFaction.SelectedValue;
        }
    }
}
